
package com.probiz.estore.core.controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import com.probiz.estore.Constants;
import com.probiz.estore.core.util.ContextUtil;
import com.probiz.estore.core.view.DownloadView;

public class Log4jMgrController extends BaseController {
	private final static  String	DEBUG				= "DEBUG";

	private final static  String	ERROR				= "ERROR";

	private final static  String	FATAL				= "FATAL";

	private final static  String	INFO				= "INFO";

	private final static  String	OFF					= "OFF";

	private final static  String	defaultView			= "tool/log4jMgr";

	private final static  String	PARAM_BEG			= "log4j.logger.";

	private final static  String	WARN				= "WARN";
	
	private final static  String	EXTRA_LOG4J_CONFIG	= "extra_log4j_config";


	public ModelAndView defaultAction(HttpServletRequest req,HttpServletResponse resp) throws ServletException {
		return getBaseView();
	}
	private ModelAndView getBaseView() throws ServletException{
		Properties configProp = getConfigProp();
		List loggers = getConfigLoggers(configProp);
		ModelAndView mv = new ModelAndView(defaultView);
		mv.addObject("logger", loggers);
		mv.addObject("originalLoggerLevel", getOriginalLoggerLevel(loggers,configProp));
		mv.addObject("currentLoggerLevel", getCurrentLoggerLevel(loggers));
		mv.addObject("extraLoggerList", getExtraLoggerList());
		return mv;
	}
	/**
	 * 下载日志
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 */
	public ModelAndView downloadLog(HttpServletRequest request,
			HttpServletResponse response) throws ServletException {
		String path = ContextUtil.getServletContext().getRealPath("/WEB-INF/logs/"+ ContextUtil.getServletContext().getServletContextName()+ ".log");
		ModelAndView mv = new ModelAndView(new DownloadView(path));
		return mv;
	}

	/**
	 * 保存当前日志等级
	 */
	public ModelAndView save(HttpServletRequest request,
			HttpServletResponse response) throws ServletException {
		Properties configProp = getConfigProp();
		List loggers = getConfigLoggers(configProp);
		for (int i = 0; i < loggers.size(); i++) {
			String pattern = (String) loggers.get(i);
			String level = request.getParameter(pattern);
			setLogger(pattern, level); // set into log4j
		}
		//start:保存自定义
		Properties pp = getExtraConfigLoggers();
		if (pp != null && !pp.isEmpty()) {
			Iterator it = pp.keySet().iterator();
			while (it.hasNext()) {
				String pattern = (String) it.next();
				String level = request.getParameter("extra_" + pattern);
				pp.put(pattern, level);
				setLogger(pattern, level);
			}
		}
		//end:保存自定义
		String message = getMessage("log4jMgr.updated");
		saveMessage(request, message);
		return new ModelAndView(new RedirectView("log4jMgr.html"));
	}
	
	/**
	 * 重设
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 */
	public ModelAndView resetAll(HttpServletRequest request,
			HttpServletResponse response) throws ServletException {
		String path = ContextUtil.getServletContext().getRealPath(Constants.LOG4J_CONFIG_LOCATION);
		// reset all configure
		PropertyConfigurator.configure(path);
		String message = getMessage("log4jMgr.reseted");
		saveMessage(request, message);
		return new ModelAndView(new RedirectView("log4jMgr.html"));
	}
	/**
	 * 添加自定义日志等级
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 */
	public ModelAndView addExtraLogger(HttpServletRequest request,	HttpServletResponse response) throws ServletException {
		String pattern = request.getParameter("pattern");
		String level = request.getParameter("level");
		Properties extraLoggerProproties = getExtraConfigLoggers();
		if (extraLoggerProproties == null || extraLoggerProproties.isEmpty()) {
			extraLoggerProproties = new Properties();
			ContextUtil.getServletContext().setAttribute(EXTRA_LOG4J_CONFIG, extraLoggerProproties);
		}
		extraLoggerProproties.put(pattern, level);
		setLogger(pattern, level);
		String message = getMessage("log4jMgr.added",new Object[]{pattern});
		saveMessage(request, message);
		return new ModelAndView(new RedirectView("log4jMgr.html"));
	}
	/**
	 * 删除自定义日志等级
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 */
	public ModelAndView removeExtraLogger(HttpServletRequest request,	HttpServletResponse response) throws ServletException {
		String pattern = request.getParameter("pattern");
		Properties extraLoggerProproties = getExtraConfigLoggers();
		extraLoggerProproties.remove(pattern);
		Logger lg = org.apache.log4j.LogManager.getLogger(pattern);
		lg.setLevel(org.apache.log4j.Level.OFF); //等同于删除
		String message = getMessage("log4jMgr.deleted",new Object[]{pattern});
		saveMessage(request, message);
		return new ModelAndView(new RedirectView("log4jMgr.html"));
	}

	
	/**
	 * 从log4j.properties中读取所有properties
	 * 
	 * @return
	 * @throws ServletException
	 */
	private Properties getConfigProp() throws ServletException {
		String path = ContextUtil.getServletContext().getRealPath(Constants.LOG4J_CONFIG_LOCATION);
		Properties rs = null;
		try {
			rs = new Properties();
			rs.load(new FileInputStream(path));
		} catch (IOException e) {
			logger.error(e);
			throw new ServletException(e);
		}
		return rs;
	}

	
	/**
	 * 从log4j.properties中的properties读取所有logger。  
	 * 所有logger以"log4j.logger"开始。例如: log4j.logger.com.opensymphony.oscache,log4j.logger.*
	 * @param pp  log4j.properties
	 * @return
	 */
	private List<String> getConfigLoggers(Properties pp) {
		List<String> rs = new ArrayList<String>();
		Iterator it = pp.keySet().iterator();
		while (it.hasNext()) {
			String key = (String) it.next();
			if (key.startsWith(PARAM_BEG)) {
				rs.add(key.substring(PARAM_BEG.length()));
			}
		}
		Collections.sort(rs);
		return rs;
	}
	/**
	 * 获得原始logger的日志等级，注意由于有些logger带appendar，所以必须把appendar过滤，例如“log4j.logger.com.probiz.estore.imports=INFO,IMPORT”
	 * @param loggers
	 * @param pp
	 * @return
	 */
	private Properties getOriginalLoggerLevel(List<String> loggers,Properties pp){
		Properties rs = new Properties();
		for (int i = 0; i < loggers.size(); i++) {
			String value = (String)pp.getProperty(PARAM_BEG+loggers.get(i));
			if(value.indexOf(",")!=-1){
				value = value.substring(0,value.indexOf(","));
			}
			rs.put(loggers.get(i), value);
		}
		return rs;
	}
	
	/**
	 * 获得自定义日志
	 * @return
	 */
	private Properties getExtraConfigLoggers() {
		Properties pp = (Properties) ContextUtil.getServletContext().getAttribute(EXTRA_LOG4J_CONFIG);
		return pp;
	}
	/**
	 * 获得自定义日志列表，界面显示
	 * @return
	 */
	private List<LogItem> getExtraLoggerList(){
		Properties pp = getExtraConfigLoggers();
		List<LogItem> list = new ArrayList<LogItem>();
		if (pp == null || pp.isEmpty()) {
			return list;
		}
		Iterator it = pp.keySet().iterator();
		while (it.hasNext()) {
			String key = (String) it.next();
			list.add(new LogItem(key,pp.getProperty(key)));
		}
		return list;
	}

	
	/**
	 * 读取当前logger的日志等级
	 * @param loggers
	 * @return
	 */
	private Properties getCurrentLoggerLevel(List loggers) {
		Properties rs = new Properties();
		for (int i = 0; i < loggers.size(); i++) {
			String pattern = (String) loggers.get(i);
			Logger lg = org.apache.log4j.LogManager.getLogger(pattern);
			if(null != lg.getLevel()){
				rs.put(loggers.get(i), lg.getLevel());
			}
		}
		return rs;
	}


	/**
	 * set logger into log4j,runtime.
	 * 
	 * @param paramKey
	 * @param level
	 */
	private void setLogger(String pattern, String level) {
		Logger lg = org.apache.log4j.LogManager.getLogger(pattern);
		if (DEBUG.equals(level)) {
			lg.setLevel(org.apache.log4j.Level.DEBUG);
		} else if (INFO.equals(level)) {
			lg.setLevel(org.apache.log4j.Level.INFO);
		} else if (WARN.equals(level)) {
			lg.setLevel(org.apache.log4j.Level.WARN);
		} else if (ERROR.equals(level)) {
			lg.setLevel(org.apache.log4j.Level.ERROR);
		} else if (FATAL.equals(level)) {
			lg.setLevel(org.apache.log4j.Level.FATAL);
		} else if (OFF.equals(level)) {
			lg.setLevel(org.apache.log4j.Level.OFF);
		}
	}
	
	public class LogItem{
		private String pattern;
		private String level;
		public String getPattern() {
			return pattern;
		}
		public void setPattern(String pattern) {
			this.pattern = pattern;
		}
		public String getLevel() {
			return level;
		}
		public void setLevel(String level) {
			this.level = level;
		}
		public LogItem(String pattern ,String level){
			this.pattern = pattern;
			this.level = level;
		}
		
	}
}
